Date: Fri May 8 04:34:05 2020
Scientist: Rasika Hudlikar
Sequencing (Waksman): Dibyendu Kumar
Statistics: Davit Sargsyan
Principal Investigator: Ah-Ng Kong

# Taxonomic Ranks:
# **K**ing **P**hillip **C**an n**O**t **F**ind **G**reen **S**ocks
# * Kingdom                
# * Phylum                    
# * Class                   
# * Order                   
# * Family     
# * Genus     
# * Species  
# options(stringsAsFactors = FALSE,
#         scipen = 999)
# # Increase mmemory size to 64 Gb----
# invisible(utils::memory.limit(65536))
# str(knitr::opts_chunk$get())
# # NOTE: the below does not work!
# knitr::opts_chunk$set(echo = FALSE, 
#                       message = FALSE,
#                       warning = FALSE,
#                       error = FALSE)
# require(knitr)
# require(kableExtra)
require(phyloseq)
Loading required package: phyloseq
# require(shiny)
require(data.table)
Loading required package: data.table
data.table 1.12.2 using 18 threads (see ?getDTthreads).  Latest news: r-datatable.com
require(ggplot2)
Loading required package: ggplot2
require(plotly)
Loading required package: plotly

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
require(DT)
Loading required package: DT
require(lmerTest)
Loading required package: lmerTest
Loading required package: lme4
Loading required package: Matrix

Attaching package: ‘lmerTest’

The following object is masked from ‘package:lme4’:

    lmer

The following object is masked from ‘package:stats’:

    step
require(taxize)
Loading required package: taxize
source("source/functions_may2019.R")
# On Windows set multithread=FALSE----
mt <- TRUE

1 Introduction

A/J inbred mice from the Jackson Laboratory are used to model cancer and for carcinogen testing given their high susceptibility to carcinogen-induced tumors.

From Cayman Chemical:Diallyl sulfide is a thioether found in garlic that can modulate the cytochrome P450 drug metabolizing system, activate the constitutive androstane receptor to regulate multidrug resistance-associated proteins, and upregulate the expression of detoxifying enzymes. Garlic-derived organosulfides such as diallyl sulfide have been shown to be highly protective from chemically-induced carcinogenesis in animals.

Nicotine-derived nitrosamine ketone (NNK) is one of the key tobacco-specific nitrosamines derived from nicotine. It plays an important role in carcinogenesis.

Nine (9) A/J mice were used in this study, 3 in each of the 3 treatment groups: Vehicle control (VC), NNK control and NNK+DAS. The study design is as follows:

DAS in corn oil was force-fed to mice throghout the study (weeks 0 to 6). A single dose of 24uM/0.1mL NNK suspended in glyceryl trioctate vehicle was injected at Week 1 intraperetoneally (IP). The vehicvle control group received vehicle only. Fecal samples were collected at 4 timepoints: before DAS treatment began (Week 0), and 1, 2 and 4 weeks after pretreatment (Week 1, Week 2 and Week 4 respectively).

2 Data preprocessing

2.1 Raw Data

FastQ files were downloaded from Rutgers Box. A total of 72 files (2 per sample, pair-ended) were downloaded.

2.2 Script

This script (nrf2ubiome_dada2_jan2020_v1.Rmd) was developed using DADA2 Pipeline Tutorial (1.12) with tips and tricks from the University of Maryland Shool of Medicine Institute for Genome Sciences (IGS) Microbiome Analysis Workshop (April 8-11, 2019). The output of the DADA2 script (data_jan2020/ps_jan2020.RData) is explored in this document.

3 Meta data: sample description

# Load data----
# Counts
load("data_jan2020/ps_jan2020.RData")
ps_jan2020@sam_data
Sample Data:        [36 samples by 4 sample variables]:
# Taxonomy
load("data_jan2020/taxa.RData")
taxa <- data.table(seq16s = rownames(taxa),
                   taxa)
head(taxa)

4 Samples

ps_jan2020@sam_data$Treatment <- factor(ps_jan2020@sam_data$Treatment,
                                        levels = c("NNK control",
                                                   "Vehicle control (VC)",
                                                   "NNK+DAS"))
ps_jan2020@sam_data$ID <- factor(ps_jan2020@sam_data$ID,
                                 levels = unique(ps_jan2020@sam_data$ID))
ps_jan2020@sam_data$Week <- factor(ps_jan2020@sam_data$Week,
                                   levels = c("Week0",
                                              "Week1",
                                              "Week2",
                                              "Week4"))
samples <- ps_jan2020@sam_data
datatable(samples,
          rownames = FALSE,
          options = list(pageLength = nrow(samples)))

5 Prune data

The OTUs were mapped to Bacteria (98.45%) and Eukaryota (1.30%) kingdoms, and 16 OTUs (0.26%) undefined.

The total of 6,174 unique sequences were found. Out of those, 6,078 were mapped to bacterial genomes.

dim(ps_jan2020@otu_table@.Data)
[1]   36 6174
# Remove OTU not mapped to Bacteria
ps0 <- subset_taxa(ps_jan2020, 
                   Kingdom == "Bacteria")
dim(ps0@otu_table@.Data)
[1]   36 6078

6 OTU table (first 10 rows)

7 Total counts per sample (i.e. sequencing depth)

p1 <- ggplot(smpl,
             aes(x = Sample,
                 y = Total,
                 fill = Treatment)) +
  facet_wrap(~ Week, 
             scale = "free_x") +
  geom_bar(stat = "identity",
           color = "black") +
  scale_x_discrete("") +
  scale_y_continuous("Number of Reads") +
  scale_fill_grey("Treatment", 
                  start = 0.1, 
                  end = 1,
                  na.value = "red",
                  aesthetics = "fill") +
  theme_bw() + 
  theme(panel.border = element_blank(), 
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        axis.title.x = element_blank(),
        # axis.text.x = element_blank(),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1),
        # axis.ticks.x=element_blank(),
        legend.position = "top")
tiff(filename = "tmp/seq_depth_jan20.tiff",
     height =6,
     width = 6,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()
print(p1)

Out of the 6,078 OTUs 6,044 belonged to 13 Phylum. 34 of the OTUs (or 0.56% of bacterial OTUs) could not be mapped to a phylum.

t2 <- data.table(table(tax_table(ps0)[, "Phylum"],
                                  exclude = NULL))
t2$V1[is.na(t2$V1)] <- "Unknown"
setorder(t2, -N)
t2[, pct := N/sum(N)]
setorder(t2, -N)
colnames(t2) <- c("Phylum",
                  "Number of OTUs",
                  "Percent of OTUs")
datatable(t2,
          rownames = FALSE,
          caption = "Number of Bacterial OTUs by Phylum",
          class = "cell-border stripe",
          options = list(search = FALSE,
                         pageLength = nrow(t2))) %>%
  formatCurrency(columns = 2,
                 currency = "",
                 mark = ",",
                 digits = 0) %>%
  formatPercentage(columns = 3,
                   digits = 2)

8 Remove Phylum

Remove:
1. Unmapped OTUs (“Unknown”).
2. Cyanobacteria: aerobic, photosynthesizing bacteria that probably got into the sample through food.
NOTE: Chloroflexi might be ok.

ps0 <- subset_taxa(ps0,
                   (!(Phylum %in% c("Unknown",
                                   "Cyanobacteria"))))

9 Richness (Alpha diversity)

Shannon index (aka Shannon enthrophy) is calculated as:
H’ = -sum(1 to R)p(i)ln(p(i)) When there is exactly 1 type of data (e.g. a single species in the sample), H’=0. The opposite scenario is when there are R>1 species present in the sample in the exact same amounts and H’=ln(R).

Shannon’s diversity index was calculated for each sample and ploted over time.

shannon.ndx <- estimate_richness(ps0,
                                 measures = "Shannon")
shannon.ndx <- data.table(Sample = rownames(shannon.ndx),
                          shannon.ndx)
smpl <- merge(smpl,
              shannon.ndx,
              by = "Sample")
p1 <- ggplot(smpl,
             aes(x = Total,
                 y = Shannon,
                 fill = Treatment,
                 shape = Week)) +
  geom_point(size = 2) +
  scale_shape_manual(breaks = unique(smpl$Week),
                     values = 21:24)
tiff(filename = "tmp/shannon_vs_depth_jan20.tiff",
     height = 5,
     width = 6,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()
ggplotly(p1)

Even though estimate_richness function does not adjust for the sequencing depth, there is no correlation between the index and the sample’s sequecing depth. Proceed with the comparison.

10 Shannon idex over time

p1 <- plot_richness(ps0,
                    x = "Week", 
                    measures = "Shannon") +
  facet_wrap(~ Treatment) +
  geom_line(aes(group = ID),
            color = "black") +
  geom_point(aes(fill = Treatment),
             shape = 21,
             size = 3,
             color = "black") +
  scale_x_discrete("") +
  theme(axis.text.x = element_text(angle = 30,
                                   hjust = 1,
                                   vjust = 1))
ggplotly(p = p1,
         tooltip = c("ID",
                     "value"))

p1 <- p1 + 
  scale_fill_discrete("") +
  theme(legend.position = "top")
tiff(filename = "tmp/shannon.tiff",
     height = 4,
     width = 5,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()

11 Average Shannon Index

# Average shannon index by treatment group
tmp <- data.table(copy(smpl))
tmp[, mu := mean(Shannon),
    by = list(Treatment,
              Week)]
tmp[, sem := sd(Shannon)/sqrt(.N),
    by = list(Treatment,
              Week)]
tmp <- unique(tmp[, c("Treatment",
                      "Week",
                      "mu",
                      "sem")])
p1 <- ggplot(tmp,
             aes(x = Week,
                 y = mu,
                 ymin = mu - sem,
                 ymax = mu + sem,
                 fill = Treatment,
                 group = Treatment)) +
  # facet_wrap(~ Genotype,
  #            scale = "free_x") +
  geom_errorbar(position = position_dodge(0.3),
                width = 0.4) +
  geom_line(position = position_dodge(0.3)) +
  geom_point(size = 3,
             shape = 21,
             position = position_dodge(0.3)) +
  scale_x_discrete("") +
  scale_y_continuous("Shannon Index") +
  scale_fill_grey("Treatment", 
                  start = 0, 
                  end = 1,
                  na.value = "red",
                  aesthetics = "fill") +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        # panel.border = element_blank(), 
        axis.title.x = element_blank(),
        # axis.text.x = element_blank(),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1),
        axis.ticks.x=element_blank(),
        legend.position = "top")
tiff(filename = "tmp/avg_shannon_jan20.tiff",
     height = 4,
     width = 5,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()
print(p1)

12 Firmicutes vs. Bacteriotides

counts_p <- counts_by_tax_rank(dt1 = otu,
                               aggr_by = "Phylum")
fb <- t(counts_p[Phylum %in% c("Firmicutes",
                               "Bacteroidetes"), -1])
fb <- data.table(Sample = rownames(fb),
                 Firmicutes = fb[, 2],
                 Bacteroidetes = fb[, 1])
fb <- data.table(merge(smpl,
            fb,
            by = "Sample"))
lims <- log2(range(c(fb$Firmicutes,
                     fb$Bacteroidetes)))
p1 <- ggplot(fb,
             aes(x = log2(Firmicutes),
                 y = log2(Bacteroidetes),
                 fill = Treatment)) +
  geom_point(size = 2,
             color = "black",
             shape = 21) +
  geom_abline(slope = 1,
              intercept = 0,
              linetype = "dashed") +
  scale_x_continuous(limits = lims) +
  scale_y_continuous(limits = lims) +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())
p2 <- ggplot(fb,
             aes(x = Week,
                 y = Firmicutes/Bacteroidetes,
                 fill = Treatment,
                 group = Treatment)) +
  geom_hline(yintercept = 1,
             linetype = "dashed") +
  geom_point(size = 2,
             color = "black",
             shape = 21,
             position = position_dodge(0.3))  +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        axis.title.x = element_blank(),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1),
        legend.position = "none")
tiff(filename = "tmp/bact_vs_firm_jan20.tiff",
     height = 7,
     width = 5,
     units = "in",
     res = 600,
     compression = "lzw+p")
gridExtra::grid.arrange(p1, p2)
graphics.off()
gridExtra::grid.arrange(p1, p2)

fb[, F_B := Firmicutes/Bacteroidetes]
fb[, log2_F_B := log2(F_B)]
m1 <- lm(log2_F_B ~ 0 + Week*Treatment,
         data = fb)
s1 <- summary(m1)
ci1 <- confint(m1)
t1 <- data.table(Term = rownames(s1$coefficients),
                 Ratio = round(2^s1$coefficients[, 1], 3),
                 `95% C.I.L.L.` = round(2^ci1[, 1], 3),
                 `95% C.I.U.L.` = round(2^ci1[, 2], 3),
                 `p-Value` = round(s1$coefficients[, 4], 3),
                 Sign = "")
t1$Sign[t1$`p-Value` < 0.05] <- "*"
t1$Sign[t1$`p-Value` < 0.01] <- "**"
t1$`p-Value`[t1$`p-Value` < 0.001] <- "<0.001"
datatable(t1,
          rownames = FALSE,
          class = "cell-border stripe")

fb[, mu := mean(Firmicutes/Bacteroidetes),
   by = c("Treatment",
          "Week")]
fb[, sem := sd(Firmicutes/Bacteroidetes)/sqrt(.N),
   by = c("Treatment",
          "Week")]
mufb <- unique(fb[, c("Treatment",
                      "Week",
                      "mu",
                      "sem")])
p3 <- ggplot(mufb,
             aes(x = Week,
                 y = mu,
                 ymin = mu - sem,
                 ymax = mu + sem,
                 fill = Treatment,
                 group = Treatment)) +
  geom_hline(yintercept = 1,
             linetype = "dashed") +
  geom_errorbar(position = position_dodge(0.3),
                width = 0.4) +
  geom_line(position = position_dodge(0.3)) +
  geom_point(size = 3,
             shape = 21,
             position = position_dodge(0.3)) +
  scale_x_discrete("") +
  scale_y_continuous("Firmicutes/Bacteroidetes") +
  # scale_fill_grey("Treatment", 
  #                 start = 0, 
  #                 end = 1,
  #                 na.value = "red",
  #                 aesthetics = "fill") +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        axis.title.x = element_blank(),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1),
        legend.position = "none")
tiff(filename = "tmp/avg_firm_bact_jan20.tiff",
     height = 4,
     width = 6,
     units = "in",
     res = 600,
     compression = "lzw+p")
print(p3)
graphics.off()
print(p3)

mufb[, est := paste0(round(mu, 2),
                     "(",
                     round(sem, 2),
                     ")")]
t1 <- dcast.data.table(mufb,
                       Treatment ~ Week,
                       value.var = "est")
datatable(t1,
          rownames = FALSE,
          class = "cell-border stripe",
          caption = "Average Ratio and SD of Firmicutes to Bacteroidetes",
          options = list(search = FALSE,
                         pageLength = nrow(t1)))

13 Alternative Fig 7

tiff(filename = "tmp/firm_vs_bact_jan20.tiff",
     height = 7,
     width = 5,
     units = "in",
     res = 600,
     compression = "lzw+p")
gridExtra::grid.arrange(p1, p3)
graphics.off()
gridExtra::grid.arrange(p1, p3)

14 Update OTU table: excuded unknown phylum and Cyanobacteria

otu <- data.table(ps0@tax_table@.Data,
                  t(ps0@otu_table@.Data))
dim(otu)
[1] 6064   42

15 1. Phylum

15.1 Counts at Phylum level

15.2 Relative abundance (%) at Phylum level

[1] "Range of relative abundance of Bacteroidetes and Firmicutes combined (%)"
[1] 74.8 99.6

15.3 PCA at Phylum level

dt_pca <- t(ra_p[, 2:ncol(ra_p)])
colnames(dt_pca) <- ra_p$Phylum
dt_pca_p <- data.table(Sample = rownames(dt_pca),
                       dt_pca)
dt_pca_p <- merge(smpl,
                  dt_pca_p,
                  by = "Sample")
# Keep only the phylum with non-zero counts
tmp <- dt_pca_p[, 7:ncol(dt_pca_p)]
keep_p <- colnames(tmp)[colSums(tmp) > 0]
dt_pca <- dt_pca[, keep_p]
# m1 <- prcomp(dt_pca,
#              center = TRUE,
#              scale. = TRUE)
# m1 <- prcomp(dt_pca,
#              center = FALSE,
#              scale. = FALSE)
m1 <- prcomp(dt_pca,
             center = TRUE,
             scale. = FALSE)
summary(m1)
Importance of components:
                          PC1     PC2      PC3      PC4       PC5       PC6       PC7       PC8       PC9
Standard deviation     0.1239 0.04443 0.003799 0.001111 0.0008556 0.0002046 4.002e-05 2.329e-05 2.002e-05
Proportion of Variance 0.8852 0.11388 0.000830 0.000070 0.0000400 0.0000000 0.000e+00 0.000e+00 0.000e+00
Cumulative Proportion  0.8852 0.99905 0.999880 0.999960 1.0000000 1.0000000 1.000e+00 1.000e+00 1.000e+00
                            PC10      PC11
Standard deviation     1.434e-05 3.832e-06
Proportion of Variance 0.000e+00 0.000e+00
Cumulative Proportion  1.000e+00 1.000e+00
# Select PC-s to pliot (PC1 & PC2)
choices <- 1:2
# Add meta data
dt.scr <- data.table(m1$x[, choices])
dt.scr$Sample <- rownames(m1$x)
dt.scr <- merge(smpl,
                dt.scr,
                by = "Sample")
dt.scr
# Loadings, i.e. arrows (df.v)
dt.rot <- as.data.frame(m1$rotation[, choices])
dt.rot$feat <- rownames(dt.rot)
dt.rot <- data.table(dt.rot)
dt.rot
dt.load <- melt.data.table(dt.rot,
                           id.vars = "feat",
                           measure.vars = 1:2,
                           variable.name = "pc",
                           value.name = "loading")
dt.load$feat <- factor(dt.load$feat,
                       levels = unique(dt.load$feat))
# Plot loadings
p0 <- ggplot(data = dt.load,
             aes(x = feat,
                 y = loading)) +
  facet_wrap(~ pc,
             nrow = 2) +
  geom_bar(stat = "identity") +
  ggtitle("PC Loadings") +
  theme(plot.title = element_text(hjust = 0.5),
        axis.text.x = element_text(angle = 45,
                                   hjust = 1))
p0
tiff(filename = "tmp/pc.1.2_loadings_phylum.tiff",
     height = 5,
     width = 6,
     units = 'in',
     res = 300,
     compression = "lzw+p")
print(p0)
graphics.off()
print(p0)

# Axis labels
u.axis.labs <- paste(colnames(dt.rot)[1:2], 
                     sprintf('(%0.1f%% explained var.)', 
                             100*m1$sdev[choices]^2/sum(m1$sdev^2)))
u.axis.labs
[1] "PC1 (88.5% explained var.)" "PC2 (11.4% explained var.)"
cntr <- data.table(aggregate(x = dt.scr$PC1,
                             by = list(dt.scr$Treatment,
                                       dt.scr$Week),
                             FUN = "mean"),
                   aggregate(x = dt.scr$PC2,
                             by = list(dt.scr$Treatment,
                                       dt.scr$Week),
                             FUN = "mean")$x)
colnames(cntr) <- c("Treatment",
                    "Week",
                    "PC1",
                    "PC2")
cntr$tmp <- factor(cntr$Treatment,
                   levels = c("NNK control",
                              "Vehicle control (VC)",
                              "NNK+DAS"),
                   labels = c("NNK",
                              "VC",
                              "NNK+DAS"))
cntr$grp <- paste(cntr$tmp,
                  cntr$Week,
                  sep = "_")
# Based on Figure p0, keep only a few variables with high loadings in PC1 and PC2----
dt.rot[, rating:= (PC1)^2 + (PC2)^2]
setorder(dt.rot, -rating)
# Select top 3
dt.rot <- dt.rot[1:3, ]
# var.keep.ndx <- which(dt.rot$feat %in% c(...))
# Or select all
# var.keep.ndx <- 3:ncol(dt1)
# Use dt.rot[var.keep.ndx,] and dt.rot$feat[var.keep.ndx]
p1 <- ggplot(data = dt.rot,
             aes(x = PC1,
                 y = PC2)) +
  # coord_equal() +
  geom_point(data = dt.scr,
             aes(fill = Treatment,
                 shape = factor(Week)),
             size = 3,
             alpha = 0.5) +
  geom_segment(aes(x = 0,
                   y = 0,
                   xend = 0.2*PC1,
                   yend = 0.2*PC2),
               arrow = arrow(length = unit(1/2, 'picas')),
               # size = 1, 
               color = "black") +
  geom_text(aes(x = 0.22*PC1,
                y = 0.22*PC2,
                label = dt.rot$feat),
            # size = 5,
            hjust = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[2]) +
  scale_fill_manual(name = "Treatment",
                    breaks = c("NNK control",
                               "Vehicle control (VC)",
                               "NNK+DAS"),
                    values = c("red",
                               "blue",
                               "green")) +
  scale_shape_manual(breaks = 1:4,
                     values = 21:24) +
  geom_label(data = cntr,
             aes(x = PC1,
                 y = PC2,
                 label = grp,
                 colour = Treatment),
             alpha = 0.5,
             size = 3) +
  scale_color_manual(guide = FALSE,
                     breaks = c("NNK control",
                                "Vehicle control (VC)",
                                "NNK+DAS"),
                     values = c("red",
                                "blue",
                                "green")) +
  ggtitle("") +
  theme_bw() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = "none")
tiff(filename = "tmp/phylum_biplot_trt_jan20.tiff",
     height = 7,
     width = 7,
     units = 'in',
     res = 300,
     compression = "lzw+p")
print(p1)
graphics.off()
ggplotly(p1)
geom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issuesgeom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issuesgeom_GeomLabel() has yet to be implemented in plotly.
  If you'd like to see this geom implemented,
  Please open an issue with your example code at
  https://github.com/ropensci/plotly/issues

# Generic biplot
biplot(m1)

15.4 3. Order

15.5 4. Family

16 5. Genus

16.1 Counts at Genus level

16.2 Relative abundance (%) at Genus level

17 Dr. Kong’s request: find the following bacterial species (emialed on 05/04/20, 11:48 AM):

18 Streptococcus bovis, H. pylori, Fusobacterium nucleatum, Enterococcus faecalis, Lactobacillus acidophilus and Bifidobacterium longum.

20 Tutorial: rOpenSci taxize tutorial

specieslist <- c("Streptococcus bovis",
                 "Helicobacter pylori",
                 "Fusobacterium nucleatum",
                 "Enterococcus faecalis",
                 "Lactobacillus acidophilus",
                 "Bifidobacterium longum")
t1 <- tax_name(query = c(specieslist),
               get = c("phylum",
                       "class",
                       "order",
                       "family",
                       "genus"), 
               db = "ncbi")
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
══  1 queries  ═══════════════

Retrieving data for taxon 'Streptococcus bovis'
✔  Found:  Streptococcus+bovis
══  Results  ═════════════════

● Total: 1 
● Found: 1 
● Not Found: 0
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
══  1 queries  ═══════════════

Retrieving data for taxon 'Helicobacter pylori'
✔  Found:  Helicobacter+pylori
══  Results  ═════════════════

● Total: 1 
● Found: 1 
● Not Found: 0
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
══  1 queries  ═══════════════

Retrieving data for taxon 'Fusobacterium nucleatum'
✔  Found:  Fusobacterium+nucleatum
══  Results  ═════════════════

● Total: 1 
● Found: 1 
● Not Found: 0
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
══  1 queries  ═══════════════

Retrieving data for taxon 'Enterococcus faecalis'
✔  Found:  Enterococcus+faecalis
══  Results  ═════════════════

● Total: 1 
● Found: 1 
● Not Found: 0
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
══  1 queries  ═══════════════

Retrieving data for taxon 'Lactobacillus acidophilus'
✔  Found:  Lactobacillus+acidophilus
══  Results  ═════════════════

● Total: 1 
● Found: 1 
● Not Found: 0
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
══  1 queries  ═══════════════

Retrieving data for taxon 'Bifidobacterium longum'
✔  Found:  Bifidobacterium+longum
══  Results  ═════════════════

● Total: 1 
● Found: 1 
● Not Found: 0
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
# Genus these species belong to, found in this dataset
t1.1 <- unique(taxa[Genus %in% t1$genus, -1])
t1.1
# Count number of OTUs in each of these genus (in this data)
find_genus <- unique(otu[Genus %in% t1.1$Genus, ])
find_genus
tbl1 <- data.table(table(find_genus$Genus))
colnames(tbl1) <- c("Genus",
                    "N_OTU")
# Number of species in each of these genus (in NCBI reference database)
rm(t2.1)
gc()
          used  (Mb) gc trigger  (Mb) max used  (Mb)
Ncells 4635595 247.6    7344555 392.3  7344555 392.3
Vcells 8898860  67.9   17824054 136.0 14784094 112.8
# NOTE: this does not work every time - KEEP TRYING until it does!
t2.1 <- downstream(x = t1$genus,
                   downto = "species",
                   db = "ncbi")
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
══  6 queries  ═══════════════

Retrieving data for taxon 'Streptococcus'
✔  Found:  Streptococcus

Retrieving data for taxon 'Helicobacter'
✔  Found:  Helicobacter

Retrieving data for taxon 'Fusobacterium'
✔  Found:  Fusobacterium

Retrieving data for taxon 'Enterococcus'
✔  Found:  Enterococcus

Retrieving data for taxon 'Lactobacillus'
✔  Found:  Lactobacillus

Retrieving data for taxon 'Bifidobacterium'
✔  Found:  Bifidobacterium
══  Results  ═════════════════

● Total: 6 
● Found: 6 
● Not Found: 0
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
No ENTREZ API key provided
 Get one via taxize::use_entrez()
See https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/
tbl2 <- data.table(Genus = names(t2.1),
                   N_Species = lapply(t2.1, nrow))
# Merge number of OTUs found and number of species kown for each genus
tbl <- merge(tbl1,
             tbl2,
             by = "Genus",
             all = TRUE)
tbl$N_OTU[is.na(tbl$N_OTU)] <- 0
setorder(tbl, -N_OTU)
datatable(tbl,
          rownames = FALSE)
# Meand and range relative abundance of each genus
tmp <- ra_g[Genus %in% t1$genus, ]
tmp1 <- apply(tmp[, -1], 
              MARGIN = 1,
              FUN = function(a) {
                return(data.table(Mean = mean(a),
                                  SD = sd(a),
                                  Min = min(a),
                                  Max = max(a)))
              })
out <- data.table(Genus = tmp$Genus,
                  rbindlist(tmp1))
datatable(out,
          rownames = FALSE) %>%
  formatPercentage(columns = 2:4,
                   digits = 2)

21 Session Information

sessionInfo()
R version 3.5.0 (2018-04-23)
Platform: x86_64-redhat-linux-gnu (64-bit)
Running under: Red Hat Enterprise Linux Server 7.5 (Maipo)

Matrix products: default
BLAS/LAPACK: /usr/lib64/R/lib/libRblas.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] taxize_0.9.95     lmerTest_3.1-0    lme4_1.1-21       Matrix_1.2-14     DT_0.6            plotly_4.9.0     
[7] ggplot2_3.2.0     data.table_1.12.2 phyloseq_1.26.1  

loaded via a namespace (and not attached):
 [1] nlme_3.1-137        bold_1.0.0          httr_1.4.0          numDeriv_2016.8-1   tools_3.5.0        
 [6] R6_2.4.0            vegan_2.5-5         lazyeval_0.2.2      BiocGenerics_0.28.0 mgcv_1.8-23        
[11] colorspace_1.4-1    permute_0.9-5       ade4_1.7-13         withr_2.1.2         tidyselect_0.2.5   
[16] gridExtra_2.3       curl_3.3            compiler_3.5.0      cli_1.1.0           Biobase_2.42.0     
[21] xml2_1.2.0          labeling_0.3        triebeard_0.3.0     scales_1.1.0        stringr_1.4.0      
[26] digest_0.6.19       minqa_1.2.4         XVector_0.22.0      pkgconfig_2.0.2     htmltools_0.3.6    
[31] htmlwidgets_1.3     rlang_0.4.0         rstudioapi_0.10     httpcode_0.3.0      shiny_1.3.2        
[36] farver_2.0.3        zoo_1.8-5           jsonlite_1.6        crosstalk_1.0.0     dplyr_0.8.1        
[41] magrittr_1.5        biomformat_1.10.1   Rcpp_1.0.1          munsell_0.5.0       S4Vectors_0.20.1   
[46] Rhdf5lib_1.4.3      ape_5.3             lifecycle_0.1.0     stringi_1.4.3       yaml_2.2.0         
[51] MASS_7.3-49         zlibbioc_1.28.0     rhdf5_2.26.2        plyr_1.8.4          grid_3.5.0         
[56] parallel_3.5.0      promises_1.0.1      crayon_1.3.4        lattice_0.20-35     Biostrings_2.50.2  
[61] splines_3.5.0       multtest_2.38.0     knitr_1.23          pillar_1.4.0        igraph_1.2.4.1     
[66] boot_1.3-20         reshape2_1.4.3      codetools_0.2-15    stats4_3.5.0        crul_0.9.0         
[71] glue_1.3.1          nloptr_1.2.1        httpuv_1.5.1        urltools_1.7.3      foreach_1.4.4      
[76] gtable_0.3.0        purrr_0.3.2         tidyr_0.8.3         reshape_0.8.8       assertthat_0.2.1   
[81] xfun_0.7            mime_0.6            xtable_1.8-4        later_0.8.0         survival_2.41-3    
[86] viridisLite_0.3.0   tibble_2.1.3        iterators_1.0.10    IRanges_2.16.0      cluster_2.0.7-1    
LS0tCnRpdGxlOiAiR3V0IE1pY3JvYmltZSBSb2xlIGluIERpYWxseWwgU3VsZmlkZSAoREFTKSBJbmhpYml0aW5nIE5OSy1JbmR1Y2VkIENhbmNlciBpbiBBL0ogTWljZSBNb2RlbCwgSmFudWFyeSAyMDIwIGJhdGNoIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCkRhdGU6IGByIGRhdGUoKWAgICAgIApTY2llbnRpc3Q6IFtSYXNpa2EgSHVkbGlrYXJdKHJhc2lrYWh1ZGxpa2FyQGdtYWlsLmNvbSkgICAgICAKU2VxdWVuY2luZyAoV2Frc21hbik6IFtEaWJ5ZW5kdSBLdW1hcl0obWFpbHRvOmRrQHdha3NtYW4ucnV0Z2Vycy5lZHUpICAgICAgClN0YXRpc3RpY3M6IFtEYXZpdCBTYXJnc3lhbl0obWFpbHRvOnNhcmdkYXZpZEBnbWFpbC5jb20pICAgICAgClByaW5jaXBhbCBJbnZlc3RpZ2F0b3I6IFtBaC1OZyBLb25nXShtYWlsdG86a29uZ3RAcGhhcm1hY3kucnV0Z2Vycy5lZHUpIAoKYGBge30KIyBUYXhvbm9taWMgUmFua3M6CiMgKipLKippbmcgKipQKipoaWxsaXAgKipDKiphbiBuKipPKip0ICoqRioqaW5kICoqRyoqcmVlbiAqKlMqKm9ja3MKIyAqIEtpbmdkb20gICAgICAgICAgICAgICAgCiMgKiBQaHlsdW0gICAgICAgICAgICAgICAgICAgIAojICogQ2xhc3MgICAgICAgICAgICAgICAgICAgCiMgKiBPcmRlciAgICAgICAgICAgICAgICAgICAKIyAqIEZhbWlseSAgICAgCiMgKiBHZW51cyAgICAgCiMgKiBTcGVjaWVzICAKYGBgCgpgYGB7ciBzZXR1cH0KIyBvcHRpb25zKHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwKIyAgICAgICAgIHNjaXBlbiA9IDk5OSkKCiMgIyBJbmNyZWFzZSBtbWVtb3J5IHNpemUgdG8gNjQgR2ItLS0tCiMgaW52aXNpYmxlKHV0aWxzOjptZW1vcnkubGltaXQoNjU1MzYpKQoKCiMgc3RyKGtuaXRyOjpvcHRzX2NodW5rJGdldCgpKQojICMgTk9URTogdGhlIGJlbG93IGRvZXMgbm90IHdvcmshCiMga25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGQUxTRSwgCiMgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKIyAgICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLAojICAgICAgICAgICAgICAgICAgICAgICBlcnJvciA9IEZBTFNFKQoKIyByZXF1aXJlKGtuaXRyKQojIHJlcXVpcmUoa2FibGVFeHRyYSkKcmVxdWlyZShwaHlsb3NlcSkKIyByZXF1aXJlKHNoaW55KQoKcmVxdWlyZShkYXRhLnRhYmxlKQpyZXF1aXJlKGdncGxvdDIpCnJlcXVpcmUocGxvdGx5KQpyZXF1aXJlKERUKQpyZXF1aXJlKGxtZXJUZXN0KQpyZXF1aXJlKHRheGl6ZSkKCnNvdXJjZSgic291cmNlL2Z1bmN0aW9uc19tYXkyMDE5LlIiKQoKIyBPbiBXaW5kb3dzIHNldCBtdWx0aXRocmVhZD1GQUxTRS0tLS0KbXQgPC0gVFJVRQpgYGAKCiMgSW50cm9kdWN0aW9uCkEvSiBpbmJyZWQgbWljZSBmcm9tIHRoZSBKYWNrc29uIExhYm9yYXRvcnkgYXJlIHVzZWQgdG8gbW9kZWwgY2FuY2VyIGFuZCBmb3IgY2FyY2lub2dlbiB0ZXN0aW5nIGdpdmVuIHRoZWlyIGhpZ2ggc3VzY2VwdGliaWxpdHkgdG8gY2FyY2lub2dlbi1pbmR1Y2VkIHR1bW9ycy4gIAogIApGcm9tIFtDYXltYW4gQ2hlbWljYWxdKGh0dHBzOi8vd3d3LmNheW1hbmNoZW0uY29tL3Byb2R1Y3QvMjA4OTQvZGlhbGx5bC1zdWxmaWRlKTpEaWFsbHlsIHN1bGZpZGUgaXMgYSB0aGlvZXRoZXIgZm91bmQgaW4gZ2FybGljIHRoYXQgY2FuIG1vZHVsYXRlIHRoZSBjeXRvY2hyb21lIFA0NTAgZHJ1ZyBtZXRhYm9saXppbmcgc3lzdGVtLCBhY3RpdmF0ZSB0aGUgY29uc3RpdHV0aXZlIGFuZHJvc3RhbmUgcmVjZXB0b3IgdG8gcmVndWxhdGUgbXVsdGlkcnVnIHJlc2lzdGFuY2UtYXNzb2NpYXRlZCBwcm90ZWlucywgYW5kIHVwcmVndWxhdGUgdGhlIGV4cHJlc3Npb24gb2YgZGV0b3hpZnlpbmcgZW56eW1lcy4gR2FybGljLWRlcml2ZWQgb3JnYW5vc3VsZmlkZXMgc3VjaCBhcyBkaWFsbHlsIHN1bGZpZGUgaGF2ZSBiZWVuIHNob3duIHRvIGJlIGhpZ2hseSBwcm90ZWN0aXZlIGZyb20gY2hlbWljYWxseS1pbmR1Y2VkIGNhcmNpbm9nZW5lc2lzIGluIGFuaW1hbHMuICAKICAKTmljb3RpbmUtZGVyaXZlZCBuaXRyb3NhbWluZSBrZXRvbmUgKE5OSykgaXMgb25lIG9mIHRoZSBrZXkgdG9iYWNjby1zcGVjaWZpYyBuaXRyb3NhbWluZXMgZGVyaXZlZCBmcm9tIG5pY290aW5lLiBJdCBwbGF5cyBhbiBpbXBvcnRhbnQgcm9sZSBpbiBjYXJjaW5vZ2VuZXNpcy4gIAogIApOaW5lICg5KSBBL0ogbWljZSB3ZXJlIHVzZWQgaW4gdGhpcyBzdHVkeSwgMyBpbiBlYWNoIG9mIHRoZSAzIHRyZWF0bWVudCBncm91cHM6IFZlaGljbGUgY29udHJvbCAoVkMpLCBOTksgY29udHJvbCBhbmQgTk5LK0RBUy4gVGhlIHN0dWR5IGRlc2lnbiBpcyBhcyBmb2xsb3dzOiAgCiFbXShkb2NzL2FqX21pY2Vfbm5rX3N0dWR5IF9kZXNpZ24ucG5nKSAgCiAgCkRBUyBpbiBjb3JuIG9pbCB3YXMgZm9yY2UtZmVkIHRvIG1pY2UgdGhyb2dob3V0IHRoZSBzdHVkeSAod2Vla3MgMCB0byA2KS4gQSBzaW5nbGUgZG9zZSBvZiAyNHVNLzAuMW1MIE5OSyBzdXNwZW5kZWQgaW4gZ2x5Y2VyeWwgdHJpb2N0YXRlIHZlaGljbGUgd2FzIGluamVjdGVkIGF0IFdlZWsgMSBpbnRyYXBlcmV0b25lYWxseSAoSVApLiBUaGUgdmVoaWN2bGUgY29udHJvbCBncm91cCByZWNlaXZlZCB2ZWhpY2xlIG9ubHkuIEZlY2FsIHNhbXBsZXMgd2VyZSBjb2xsZWN0ZWQgYXQgNCB0aW1lcG9pbnRzOiBiZWZvcmUgREFTIHRyZWF0bWVudCBiZWdhbiAoV2VlayAwKSwgYW5kIDEsIDIgYW5kIDQgd2Vla3MgYWZ0ZXIgcHJldHJlYXRtZW50IChXZWVrIDEsIFdlZWsgMiBhbmQgV2VlayA0IHJlc3BlY3RpdmVseSkuICAKCiMgRGF0YSBwcmVwcm9jZXNzaW5nCiMjIFJhdyBEYXRhIApGYXN0USBmaWxlcyB3ZXJlIGRvd25sb2FkZWQgZnJvbSBbUnV0Z2VycyBCb3hdKGh0dHBzOi8vcnV0Z2Vycy5hcHAuYm94LmNvbS9mb2xkZXIvOTk3NTgxNjU5ODIpLiBBIHRvdGFsIG9mIDcyIGZpbGVzICgyIHBlciBzYW1wbGUsIHBhaXItZW5kZWQpIHdlcmUgZG93bmxvYWRlZC4gCgojIyBTY3JpcHQKVGhpcyBzY3JpcHQgKCoqKm5yZjJ1YmlvbWVfZGFkYTJfamFuMjAyMF92MS5SbWQqKiopIHdhcyBkZXZlbG9wZWQgdXNpbmcgW0RBREEyIFBpcGVsaW5lIFR1dG9yaWFsICgxLjEyKV0oaHR0cHM6Ly9iZW5qam5lYi5naXRodWIuaW8vZGFkYTIvdHV0b3JpYWwuaHRtbCkgd2l0aCB0aXBzIGFuZCB0cmlja3MgZnJvbSB0aGUgW1VuaXZlcnNpdHkgb2YgTWFyeWxhbmQgU2hvb2wgb2YgTWVkaWNpbmUgSW5zdGl0dXRlIGZvciBHZW5vbWUgU2NpZW5jZXMgKElHUyldKGh0dHA6Ly93d3cuaWdzLnVtYXJ5bGFuZC5lZHUvKSBbTWljcm9iaW9tZSBBbmFseXNpcyBXb3Jrc2hvcCAoQXByaWwgOC0xMSwgMjAxOSldKGh0dHA6Ly93d3cuaWdzLnVtYXJ5bGFuZC5lZHUvZWR1Y2F0aW9uL3drc2hwX21ldGFnZW5vbWUucGhwKS4gVGhlIG91dHB1dCBvZiB0aGUgREFEQTIgc2NyaXB0ICgqKipkYXRhX2phbjIwMjAvcHNfamFuMjAyMC5SRGF0YSoqKikgaXMgZXhwbG9yZWQgaW4gdGhpcyBkb2N1bWVudC4KCiMgTWV0YSBkYXRhOiBzYW1wbGUgZGVzY3JpcHRpb24KYGBge3IgZGF0YX0KIyBMb2FkIGRhdGEtLS0tCiMgQ291bnRzCmxvYWQoImRhdGFfamFuMjAyMC9wc19qYW4yMDIwLlJEYXRhIikKcHNfamFuMjAyMEBzYW1fZGF0YQoKIyBUYXhvbm9teQpsb2FkKCJkYXRhX2phbjIwMjAvdGF4YS5SRGF0YSIpCnRheGEgPC0gZGF0YS50YWJsZShzZXExNnMgPSByb3duYW1lcyh0YXhhKSwKICAgICAgICAgICAgICAgICAgIHRheGEpCmhlYWQodGF4YSkKYGBgCgojIFNhbXBsZXMKYGBge3Igc2FtcGxlc30KcHNfamFuMjAyMEBzYW1fZGF0YSRUcmVhdG1lbnQgPC0gZmFjdG9yKHBzX2phbjIwMjBAc2FtX2RhdGEkVHJlYXRtZW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiTk5LIGNvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmVoaWNsZSBjb250cm9sIChWQykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTk5LK0RBUyIpKQpwc19qYW4yMDIwQHNhbV9kYXRhJElEIDwtIGZhY3Rvcihwc19qYW4yMDIwQHNhbV9kYXRhJElELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUocHNfamFuMjAyMEBzYW1fZGF0YSRJRCkpCnBzX2phbjIwMjBAc2FtX2RhdGEkV2VlayA8LSBmYWN0b3IocHNfamFuMjAyMEBzYW1fZGF0YSRXZWVrLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIldlZWswIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlazIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlZWs0IikpCnNhbXBsZXMgPC0gcHNfamFuMjAyMEBzYW1fZGF0YQpkYXRhdGFibGUoc2FtcGxlcywKICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gbnJvdyhzYW1wbGVzKSkpCmBgYAoKIyBQcnVuZSBkYXRhClRoZSBPVFVzIHdlcmUgbWFwcGVkIHRvIEJhY3RlcmlhICg5OC40NSUpIGFuZCBFdWthcnlvdGEgKDEuMzAlKSBraW5nZG9tcywgYW5kICAxNiBPVFVzICgwLjI2JSkgdW5kZWZpbmVkLiAKCmBgYHtyIGNoZWNrX21hcHBpbmdfa2luZ2RvbSwgd2FybmluZyA9IEZBTFNFLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KdDEgPC0gZGF0YS50YWJsZSh0YWJsZSh0YXhfdGFibGUocHNfamFuMjAyMClbLCAiS2luZ2RvbSJdLAogICAgICAgICAgICAgICAgICAgICAgIGV4Y2x1ZGUgPSBOVUxMKSkKdDEkVjFbaXMubmEodDEkVjEpXSA8LSAiVW5rbm93biIKCnQxWywgcGN0IDo9IE4vc3VtKE4pXQpzZXRvcmRlcih0MSwgLU4pCgpjb2xuYW1lcyh0MSkgPC0gYygiS2luZ2RvbSIsCiAgICAgICAgICAgICAgICAgICJOdW1iZXIgb2YgT1RVcyIsCiAgICAgICAgICAgICAgICAgICJQZXJjZW50IG9mIE9UVXMiKQpkYXRhdGFibGUodDEsCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2FwdGlvbiA9ICJOdW1iZXIgb2YgT1RVcyBieSBLaW5nZG9tIiwKICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzZWFyY2ggPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSBucm93KHQxKSkpICU+JQogIGZvcm1hdEN1cnJlbmN5KGNvbHVtbnMgPSAyLAogICAgICAgICAgICAgICAgIGN1cnJlbmN5ID0gIiIsCiAgICAgICAgICAgICAgICAgbWFyayA9ICIsIiwKICAgICAgICAgICAgICAgICBkaWdpdHMgPSAwKSAlPiUKICBmb3JtYXRQZXJjZW50YWdlKGNvbHVtbnMgPSAzLAogICAgICAgICAgICAgICAgICAgZGlnaXRzID0gMikKYGBgCgpUaGUgdG90YWwgb2YgNiwxNzQgdW5pcXVlIHNlcXVlbmNlcyB3ZXJlIGZvdW5kLiBPdXQgb2YgdGhvc2UsIDYsMDc4IHdlcmUgbWFwcGVkIHRvIGJhY3RlcmlhbCBnZW5vbWVzLiAKCmBgYHtyIGtlZXBfYmFjdGVyaWF9CmRpbShwc19qYW4yMDIwQG90dV90YWJsZUAuRGF0YSkKCiMgUmVtb3ZlIE9UVSBub3QgbWFwcGVkIHRvIEJhY3RlcmlhCnBzMCA8LSBzdWJzZXRfdGF4YShwc19qYW4yMDIwLCAKICAgICAgICAgICAgICAgICAgIEtpbmdkb20gPT0gIkJhY3RlcmlhIikKZGltKHBzMEBvdHVfdGFibGVALkRhdGEpCmBgYAogIAojIE9UVSB0YWJsZSAoZmlyc3QgMTAgcm93cykKYGBge3Igb3R1X3RhYmxlLCB3YXJuaW5nPUZBTFNFLGVjaG89RkFMU0UsbWVzc2FnZT1GQUxTRX0Kb3R1IDwtIGRhdGEudGFibGUocHMwQHRheF90YWJsZUAuRGF0YSwKICAgICAgICAgICAgICAgICAgdChwczBAb3R1X3RhYmxlQC5EYXRhKSkKCiMgUmVtb3ZlIFNwZWNpZXMgbWFwcGluZycKb3R1JFNwZWNpZXMgPC0gTlVMTAoKZGF0YXRhYmxlKGhlYWQob3R1LCAxMCksCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2FwdGlvbiA9ICJUYXhvbm9taWMgIGNvdW50IHRhYmxlIiwKICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzZWFyY2ggPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSAxMCkpICU+JQogIGZvcm1hdEN1cnJlbmN5KGNvbHVtbnMgPSA3OjM2LAogICAgICAgICAgICAgICAgIGN1cnJlbmN5ID0gIiIsCiAgICAgICAgICAgICAgICAgbWFyayA9ICIsIiwKICAgICAgICAgICAgICAgICBkaWdpdHMgPSAwKQpgYGAKICAKIyBUb3RhbCBjb3VudHMgcGVyIHNhbXBsZSAoaS5lLiBzZXF1ZW5jaW5nIGRlcHRoKQpgYGB7ciBzZXFfZGVwdGhfcGxvdGx5LCB3YXJuaW5nPUZBTFNFLGVjaG89RkFMU0UsbWVzc2FnZT1GQUxTRSxmaWcud2lkdGg9MTAsZmlnLmhlaWdodD01fQp0MSA8LSBjb2xTdW1zKG90dVssIDc6bmNvbChvdHUpXSkKdDEgPC0gZGF0YS50YWJsZShTYW1wbGUgPSBuYW1lcyh0MSksCiAgICAgICAgICAgICAgICAgVG90YWwgPSB0MSkKdG1wIDwtIGFzLmRhdGEudGFibGUoc2FtcGxlc0AuRGF0YSkKY29sbmFtZXModG1wKSA8LSBzYW1wbGVzQG5hbWVzCgpzbXBsIDwtIG1lcmdlKHRtcCwKICAgICAgICAgICAgICB0MSwKICAgICAgICAgICAgICBieSA9ICJTYW1wbGUiKQoKcDEgPC0gZ2dwbG90KHNtcGwsCiAgICAgICAgICAgICBhZXMoeCA9IFNhbXBsZSwKICAgICAgICAgICAgICAgICB5ID0gVG90YWwsCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwKICAgICAgICAgICAgICAgICBjb2xvdXIgPSBXZWVrKSkgKwogIGZhY2V0X3dyYXAofiBUcmVhdG1lbnQsCiAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlIikgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgiU2FtcGxlIE5hbWUiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCJOdW1iZXIgb2YgUmVhZHMiKSArCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiR3JvdXAiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKSAKZ2dwbG90bHkocDEpCmBgYAogIApgYGB7ciBzZXFfZGVwdGhfZ3JleXNjYWxlLCBmaWcuaGVpZ2h0ID0gNiAsIGZpZy53aWR0aCA9IDZ9CnAxIDwtIGdncGxvdChzbXBsLAogICAgICAgICAgICAgYWVzKHggPSBTYW1wbGUsCiAgICAgICAgICAgICAgICAgeSA9IFRvdGFsLAogICAgICAgICAgICAgICAgIGZpbGwgPSBUcmVhdG1lbnQpKSArCiAgZmFjZXRfd3JhcCh+IFdlZWssIAogICAgICAgICAgICAgc2NhbGUgPSAiZnJlZV94IikgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLAogICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoIk51bWJlciBvZiBSZWFkcyIpICsKICBzY2FsZV9maWxsX2dyZXkoIlRyZWF0bWVudCIsIAogICAgICAgICAgICAgICAgICBzdGFydCA9IDAuMSwgCiAgICAgICAgICAgICAgICAgIGVuZCA9IDEsCiAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gInJlZCIsCiAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIpICsKICB0aGVtZV9idygpICsgCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAjIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSwKICAgICAgICAjIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCgp0aWZmKGZpbGVuYW1lID0gInRtcC9zZXFfZGVwdGhfamFuMjAudGlmZiIsCiAgICAgaGVpZ2h0ID02LAogICAgIHdpZHRoID0gNiwKICAgICB1bml0cyA9ICJpbiIsCiAgICAgcmVzID0gNjAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDEpCmdyYXBoaWNzLm9mZigpCgpwcmludChwMSkKYGBgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCiAgCk91dCBvZiB0aGUgNiwwNzggT1RVcyA2LDA0NCBiZWxvbmdlZCB0byAxMyBQaHlsdW0uIDM0IG9mIHRoZSBPVFVzIChvciAwLjU2JSBvZiBiYWN0ZXJpYWwgT1RVcykgY291bGQgbm90IGJlIG1hcHBlZCB0byBhIHBoeWx1bS4KCmBgYHtyIHBoeWx1bV9tYXBwaW5nfQp0MiA8LSBkYXRhLnRhYmxlKHRhYmxlKHRheF90YWJsZShwczApWywgIlBoeWx1bSJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhjbHVkZSA9IE5VTEwpKQp0MiRWMVtpcy5uYSh0MiRWMSldIDwtICJVbmtub3duIgpzZXRvcmRlcih0MiwgLU4pCnQyWywgcGN0IDo9IE4vc3VtKE4pXQpzZXRvcmRlcih0MiwgLU4pCgpjb2xuYW1lcyh0MikgPC0gYygiUGh5bHVtIiwKICAgICAgICAgICAgICAgICAgIk51bWJlciBvZiBPVFVzIiwKICAgICAgICAgICAgICAgICAgIlBlcmNlbnQgb2YgT1RVcyIpCgpkYXRhdGFibGUodDIsCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2FwdGlvbiA9ICJOdW1iZXIgb2YgQmFjdGVyaWFsIE9UVXMgYnkgUGh5bHVtIiwKICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzZWFyY2ggPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSBucm93KHQyKSkpICU+JQogIGZvcm1hdEN1cnJlbmN5KGNvbHVtbnMgPSAyLAogICAgICAgICAgICAgICAgIGN1cnJlbmN5ID0gIiIsCiAgICAgICAgICAgICAgICAgbWFyayA9ICIsIiwKICAgICAgICAgICAgICAgICBkaWdpdHMgPSAwKSAlPiUKICBmb3JtYXRQZXJjZW50YWdlKGNvbHVtbnMgPSAzLAogICAgICAgICAgICAgICAgICAgZGlnaXRzID0gMikKYGBgCgojIFJlbW92ZSBQaHlsdW0KUmVtb3ZlOiAgCjEuIFVubWFwcGVkIE9UVXMgKCJVbmtub3duIikuICAgIAoyLiBDeWFub2JhY3RlcmlhOiBhZXJvYmljLCBwaG90b3N5bnRoZXNpemluZyAgYmFjdGVyaWEgdGhhdCBwcm9iYWJseSBnb3QgaW50byB0aGUgc2FtcGxlIHRocm91Z2ggZm9vZC4gIApOT1RFOiBbQ2hsb3JvZmxleGkgbWlnaHQgYmUgb2suXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM0MTkyODQwLykgIAogIApgYGB7ciByZW1vdmVfcGh5bHVtc30KcHMwIDwtIHN1YnNldF90YXhhKHBzMCwKICAgICAgICAgICAgICAgICAgICghKFBoeWx1bSAlaW4lIGMoIlVua25vd24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDeWFub2JhY3RlcmlhIikpKSkKYGBgCgojIFJpY2huZXNzIChBbHBoYSBkaXZlcnNpdHkpClNoYW5ub24gaW5kZXggKGFrYSBTaGFubm9uIGVudGhyb3BoeSkgaXMgY2FsY3VsYXRlZCBhczogIApIJyA9IC1zdW0oMSB0byBSKXAoaSlsbihwKGkpKSAKV2hlbiB0aGVyZSBpcyBleGFjdGx5IDEgdHlwZSBvZiBkYXRhIChlLmcuIGEgc2luZ2xlIHNwZWNpZXMgaW4gdGhlIHNhbXBsZSksIEgnPTAuIFRoZSBvcHBvc2l0ZSBzY2VuYXJpbyBpcyB3aGVuIHRoZXJlIGFyZSBSPjEgc3BlY2llcyBwcmVzZW50IGluIHRoZSBzYW1wbGUgaW4gdGhlIGV4YWN0IHNhbWUgYW1vdW50cyBhbmQgSCc9bG4oUikuICAKICAKU2hhbm5vbidzIGRpdmVyc2l0eSBpbmRleCB3YXMgY2FsY3VsYXRlZCBmb3IgZWFjaCBzYW1wbGUgYW5kIHBsb3RlZCBvdmVyIHRpbWUuCgpgYGB7ciBzaGFubm9uX3ZzX2RlcHRoLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gNn0Kc2hhbm5vbi5uZHggPC0gZXN0aW1hdGVfcmljaG5lc3MocHMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFzdXJlcyA9ICJTaGFubm9uIikKCnNoYW5ub24ubmR4IDwtIGRhdGEudGFibGUoU2FtcGxlID0gcm93bmFtZXMoc2hhbm5vbi5uZHgpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHNoYW5ub24ubmR4KQoKc21wbCA8LSBtZXJnZShzbXBsLAogICAgICAgICAgICAgIHNoYW5ub24ubmR4LAogICAgICAgICAgICAgIGJ5ID0gIlNhbXBsZSIpCgpwMSA8LSBnZ3Bsb3Qoc21wbCwKICAgICAgICAgICAgIGFlcyh4ID0gVG90YWwsCiAgICAgICAgICAgICAgICAgeSA9IFNoYW5ub24sCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwKICAgICAgICAgICAgICAgICBzaGFwZSA9IFdlZWspKSArCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIHNjYWxlX3NoYXBlX21hbnVhbChicmVha3MgPSB1bmlxdWUoc21wbCRXZWVrKSwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gMjE6MjQpCgp0aWZmKGZpbGVuYW1lID0gInRtcC9zaGFubm9uX3ZzX2RlcHRoX2phbjIwLnRpZmYiLAogICAgIGhlaWdodCA9IDUsCiAgICAgd2lkdGggPSA2LAogICAgIHVuaXRzID0gImluIiwKICAgICByZXMgPSA2MDAsCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQpwcmludChwMSkKZ3JhcGhpY3Mub2ZmKCkKCmdncGxvdGx5KHAxKQpgYGAKCkV2ZW4gdGhvdWdoICoqKmVzdGltYXRlX3JpY2huZXNzKioqIGZ1bmN0aW9uIGRvZXMgbm90IGFkanVzdCBmb3IgdGhlIHNlcXVlbmNpbmcgZGVwdGgsIHRoZXJlIGlzIG5vIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGluZGV4IGFuZCB0aGUgc2FtcGxlJ3Mgc2VxdWVjaW5nIGRlcHRoLiBQcm9jZWVkIHdpdGggdGhlIGNvbXBhcmlzb24uCgojIFNoYW5ub24gaWRleCBvdmVyIHRpbWUKYGBge3IgcmljaG5lc3MsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA1fQpwMSA8LSBwbG90X3JpY2huZXNzKHBzMCwKICAgICAgICAgICAgICAgICAgICB4ID0gIldlZWsiLCAKICAgICAgICAgICAgICAgICAgICBtZWFzdXJlcyA9ICJTaGFubm9uIikgKwogIGZhY2V0X3dyYXAofiBUcmVhdG1lbnQpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gSUQpLAogICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3BvaW50KGFlcyhmaWxsID0gVHJlYXRtZW50KSwKICAgICAgICAgICAgIHNoYXBlID0gMjEsCiAgICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKwogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDEpKQoKZ2dwbG90bHkocCA9IHAxLAogICAgICAgICB0b29sdGlwID0gYygiSUQiLAogICAgICAgICAgICAgICAgICAgICAidmFsdWUiKSkKCnAxIDwtIHAxICsgCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQoKdGlmZihmaWxlbmFtZSA9ICJ0bXAvc2hhbm5vbi50aWZmIiwKICAgICBoZWlnaHQgPSA0LAogICAgIHdpZHRoID0gNSwKICAgICB1bml0cyA9ICJpbiIsCiAgICAgcmVzID0gNjAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDEpCmdyYXBoaWNzLm9mZigpCmBgYAoKIyBBdmVyYWdlIFNoYW5ub24gSW5kZXgKYGBge3IgYXZnX3NoYW5ub25fcGxvdCwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDV9CiMgQXZlcmFnZSBzaGFubm9uIGluZGV4IGJ5IHRyZWF0bWVudCBncm91cAp0bXAgPC0gZGF0YS50YWJsZShjb3B5KHNtcGwpKQoKdG1wWywgbXUgOj0gbWVhbihTaGFubm9uKSwKICAgIGJ5ID0gbGlzdChUcmVhdG1lbnQsCiAgICAgICAgICAgICAgV2VlayldCnRtcFssIHNlbSA6PSBzZChTaGFubm9uKS9zcXJ0KC5OKSwKICAgIGJ5ID0gbGlzdChUcmVhdG1lbnQsCiAgICAgICAgICAgICAgV2VlayldCnRtcCA8LSB1bmlxdWUodG1wWywgYygiVHJlYXRtZW50IiwKICAgICAgICAgICAgICAgICAgICAgICJXZWVrIiwKICAgICAgICAgICAgICAgICAgICAgICJtdSIsCiAgICAgICAgICAgICAgICAgICAgICAic2VtIildKQoKcDEgPC0gZ2dwbG90KHRtcCwKICAgICAgICAgICAgIGFlcyh4ID0gV2VlaywKICAgICAgICAgICAgICAgICB5ID0gbXUsCiAgICAgICAgICAgICAgICAgeW1pbiA9IG11IC0gc2VtLAogICAgICAgICAgICAgICAgIHltYXggPSBtdSArIHNlbSwKICAgICAgICAgICAgICAgICBmaWxsID0gVHJlYXRtZW50LAogICAgICAgICAgICAgICAgIGdyb3VwID0gVHJlYXRtZW50KSkgKwogICMgZmFjZXRfd3JhcCh+IEdlbm90eXBlLAogICMgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3giKSArCiAgZ2VvbV9lcnJvcmJhcihwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuMyksCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAuNCkgKwogIGdlb21fbGluZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuMykpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLAogICAgICAgICAgICAgc2hhcGUgPSAyMSwKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC4zKSkgKwogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoIlNoYW5ub24gSW5kZXgiKSArCiAgc2NhbGVfZmlsbF9ncmV5KCJUcmVhdG1lbnQiLCAKICAgICAgICAgICAgICAgICAgc3RhcnQgPSAwLCAKICAgICAgICAgICAgICAgICAgZW5kID0gMSwKICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIikgKwogIHRoZW1lX2J3KCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICMgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIyBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIikKCnRpZmYoZmlsZW5hbWUgPSAidG1wL2F2Z19zaGFubm9uX2phbjIwLnRpZmYiLAogICAgIGhlaWdodCA9IDQsCiAgICAgd2lkdGggPSA1LAogICAgIHVuaXRzID0gImluIiwKICAgICByZXMgPSA2MDAsCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQpwcmludChwMSkKZ3JhcGhpY3Mub2ZmKCkKCnByaW50KHAxKQpgYGAKCiMgRmlybWljdXRlcyB2cy4gQmFjdGVyaW90aWRlcwpgYGB7ciBmaXJtX3ZzX2JhY3QsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA1LCB3YXJuaW5nID0gRkFMU0V9CmNvdW50c19wIDwtIGNvdW50c19ieV90YXhfcmFuayhkdDEgPSBvdHUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyX2J5ID0gIlBoeWx1bSIpCgpmYiA8LSB0KGNvdW50c19wW1BoeWx1bSAlaW4lIGMoIkZpcm1pY3V0ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJhY3Rlcm9pZGV0ZXMiKSwgLTFdKQpmYiA8LSBkYXRhLnRhYmxlKFNhbXBsZSA9IHJvd25hbWVzKGZiKSwKICAgICAgICAgICAgICAgICBGaXJtaWN1dGVzID0gZmJbLCAyXSwKICAgICAgICAgICAgICAgICBCYWN0ZXJvaWRldGVzID0gZmJbLCAxXSkKZmIgPC0gZGF0YS50YWJsZShtZXJnZShzbXBsLAogICAgICAgICAgICBmYiwKICAgICAgICAgICAgYnkgPSAiU2FtcGxlIikpCgpsaW1zIDwtIGxvZzIocmFuZ2UoYyhmYiRGaXJtaWN1dGVzLAogICAgICAgICAgICAgICAgICAgICBmYiRCYWN0ZXJvaWRldGVzKSkpCgpwMSA8LSBnZ3Bsb3QoZmIsCiAgICAgICAgICAgICBhZXMoeCA9IGxvZzIoRmlybWljdXRlcyksCiAgICAgICAgICAgICAgICAgeSA9IGxvZzIoQmFjdGVyb2lkZXRlcyksCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2hhcGUgPSAyMSkgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwKICAgICAgICAgICAgICBpbnRlcmNlcHQgPSAwLAogICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gbGltcykgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBsaW1zKSArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCnAyIDwtIGdncGxvdChmYiwKICAgICAgICAgICAgIGFlcyh4ID0gV2VlaywKICAgICAgICAgICAgICAgICB5ID0gRmlybWljdXRlcy9CYWN0ZXJvaWRldGVzLAogICAgICAgICAgICAgICAgIGZpbGwgPSBUcmVhdG1lbnQsCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBUcmVhdG1lbnQpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwKICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLAogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgc2hhcGUgPSAyMSwKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC4zKSkgICsKICB0aGVtZV9idygpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnRpZmYoZmlsZW5hbWUgPSAidG1wL2JhY3RfdnNfZmlybV9qYW4yMC50aWZmIiwKICAgICBoZWlnaHQgPSA3LAogICAgIHdpZHRoID0gNSwKICAgICB1bml0cyA9ICJpbiIsCiAgICAgcmVzID0gNjAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocDEsIHAyKQpncmFwaGljcy5vZmYoKQoKZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocDEsIHAyKQpgYGAKCmBgYHtyIGF2Z19maXJtX2JhY3QsIGZpZy5oZWlnaHQgPSA3LCBmaWcud2lkdGggPSA1fQpmYlssIEZfQiA6PSBGaXJtaWN1dGVzL0JhY3Rlcm9pZGV0ZXNdCmZiWywgbG9nMl9GX0IgOj0gbG9nMihGX0IpXQoKbTEgPC0gbG0obG9nMl9GX0IgfiAwICsgV2VlaypUcmVhdG1lbnQsCiAgICAgICAgIGRhdGEgPSBmYikKczEgPC0gc3VtbWFyeShtMSkKY2kxIDwtIGNvbmZpbnQobTEpCnQxIDwtIGRhdGEudGFibGUoVGVybSA9IHJvd25hbWVzKHMxJGNvZWZmaWNpZW50cyksCiAgICAgICAgICAgICAgICAgUmF0aW8gPSByb3VuZCgyXnMxJGNvZWZmaWNpZW50c1ssIDFdLCAzKSwKICAgICAgICAgICAgICAgICBgOTUlIEMuSS5MLkwuYCA9IHJvdW5kKDJeY2kxWywgMV0sIDMpLAogICAgICAgICAgICAgICAgIGA5NSUgQy5JLlUuTC5gID0gcm91bmQoMl5jaTFbLCAyXSwgMyksCiAgICAgICAgICAgICAgICAgYHAtVmFsdWVgID0gcm91bmQoczEkY29lZmZpY2llbnRzWywgNF0sIDMpLAogICAgICAgICAgICAgICAgIFNpZ24gPSAiIikKdDEkU2lnblt0MSRgcC1WYWx1ZWAgPCAwLjA1XSA8LSAiKiIKdDEkU2lnblt0MSRgcC1WYWx1ZWAgPCAwLjAxXSA8LSAiKioiCnQxJGBwLVZhbHVlYFt0MSRgcC1WYWx1ZWAgPCAwLjAwMV0gPC0gIjwwLjAwMSIKZGF0YXRhYmxlKHQxLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIpCgpmYlssIG11IDo9IG1lYW4oRmlybWljdXRlcy9CYWN0ZXJvaWRldGVzKSwKICAgYnkgPSBjKCJUcmVhdG1lbnQiLAogICAgICAgICAgIldlZWsiKV0KZmJbLCBzZW0gOj0gc2QoRmlybWljdXRlcy9CYWN0ZXJvaWRldGVzKS9zcXJ0KC5OKSwKICAgYnkgPSBjKCJUcmVhdG1lbnQiLAogICAgICAgICAgIldlZWsiKV0KCm11ZmIgPC0gdW5pcXVlKGZiWywgYygiVHJlYXRtZW50IiwKICAgICAgICAgICAgICAgICAgICAgICJXZWVrIiwKICAgICAgICAgICAgICAgICAgICAgICJtdSIsCiAgICAgICAgICAgICAgICAgICAgICAic2VtIildKQoKcDMgPC0gZ2dwbG90KG11ZmIsCiAgICAgICAgICAgICBhZXMoeCA9IFdlZWssCiAgICAgICAgICAgICAgICAgeSA9IG11LAogICAgICAgICAgICAgICAgIHltaW4gPSBtdSAtIHNlbSwKICAgICAgICAgICAgICAgICB5bWF4ID0gbXUgKyBzZW0sCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwKICAgICAgICAgICAgICAgICBncm91cCA9IFRyZWF0bWVudCkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLAogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fZXJyb3JiYXIocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjMpLAogICAgICAgICAgICAgICAgd2lkdGggPSAwLjQpICsKICBnZW9tX2xpbmUocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjMpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMywKICAgICAgICAgICAgIHNoYXBlID0gMjEsCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuMykpICsKICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCJGaXJtaWN1dGVzL0JhY3Rlcm9pZGV0ZXMiKSArCiAgIyBzY2FsZV9maWxsX2dyZXkoIlRyZWF0bWVudCIsIAogICMgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMCwgCiAgIyAgICAgICAgICAgICAgICAgZW5kID0gMSwKICAjICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJyZWQiLAogICMgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIpICsKICB0aGVtZV9idygpICsgCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnRpZmYoZmlsZW5hbWUgPSAidG1wL2F2Z19maXJtX2JhY3RfamFuMjAudGlmZiIsCiAgICAgaGVpZ2h0ID0gNCwKICAgICB3aWR0aCA9IDYsCiAgICAgdW5pdHMgPSAiaW4iLAogICAgIHJlcyA9IDYwMCwKICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpCnByaW50KHAzKQpncmFwaGljcy5vZmYoKQoKcHJpbnQocDMpCgptdWZiWywgZXN0IDo9IHBhc3RlMChyb3VuZChtdSwgMiksCiAgICAgICAgICAgICAgICAgICAgICIoIiwKICAgICAgICAgICAgICAgICAgICAgcm91bmQoc2VtLCAyKSwKICAgICAgICAgICAgICAgICAgICAgIikiKV0KCnQxIDwtIGRjYXN0LmRhdGEudGFibGUobXVmYiwKICAgICAgICAgICAgICAgICAgICAgICBUcmVhdG1lbnQgfiBXZWVrLAogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLnZhciA9ICJlc3QiKQpkYXRhdGFibGUodDEsCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2xhc3MgPSAiY2VsbC1ib3JkZXIgc3RyaXBlIiwKICAgICAgICAgIGNhcHRpb24gPSAiQXZlcmFnZSBSYXRpbyBhbmQgU0Qgb2YgRmlybWljdXRlcyB0byBCYWN0ZXJvaWRldGVzIiwKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHNlYXJjaCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgcGFnZUxlbmd0aCA9IG5yb3codDEpKSkKYGBgCgojIEFsdGVybmF0aXZlIEZpZyA3CmBgYHtyIGZpZzdfYWx0LCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gNX0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvZmlybV92c19iYWN0X2phbjIwLnRpZmYiLAogICAgIGhlaWdodCA9IDcsCiAgICAgd2lkdGggPSA1LAogICAgIHVuaXRzID0gImluIiwKICAgICByZXMgPSA2MDAsCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShwMSwgcDMpCmdyYXBoaWNzLm9mZigpCgpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShwMSwgcDMpCmBgYAoKIyBVcGRhdGUgT1RVIHRhYmxlOiBleGN1ZGVkIHVua25vd24gcGh5bHVtIGFuZCBDeWFub2JhY3RlcmlhCmBgYHtyIHVwZGF0ZV9vdHV9Cm90dSA8LSBkYXRhLnRhYmxlKHBzMEB0YXhfdGFibGVALkRhdGEsCiAgICAgICAgICAgICAgICAgIHQocHMwQG90dV90YWJsZUAuRGF0YSkpCmRpbShvdHUpCmBgYAoKIyAxLiBQaHlsdW0KIyMgQ291bnRzIGF0IFBoeWx1bSBsZXZlbApgYGB7ciBjb3VudHNfcCwgd2FybmluZz1GQUxTRSxlY2hvPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CmNvdW50c19wIDwtIGNvdW50c19ieV90YXhfcmFuayhkdDEgPSBvdHUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyX2J5ID0gIlBoeWx1bSIpCnNldG9yZGVyKGNvdW50c19wLCAtYFJIMDFgKQpkYXRhdGFibGUoY291bnRzX3AsCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2FwdGlvbiA9ICJUYXhvbm9taWMgIGNvdW50IHRhYmxlIiwKICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzZWFyY2ggPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSBucm93KGNvdW50c19wKSkpICU+JQogIGZvcm1hdEN1cnJlbmN5KGNvbHVtbnMgPSAyOm5jb2woY291bnRzX3ApLAogICAgICAgICAgICAgICAgIGN1cnJlbmN5ID0gIiIsCiAgICAgICAgICAgICAgICAgbWFyayA9ICIsIiwKICAgICAgICAgICAgICAgICBkaWdpdHMgPSAwKQpgYGAKCiMjIFJlbGF0aXZlIGFidW5kYW5jZSAoJSkgYXQgUGh5bHVtIGxldmVsCmBgYHtyIHJhX3AsIHdhcm5pbmc9RkFMU0UsZWNobz1GQUxTRSxtZXNzYWdlPUZBTFNFfQpyYV9wIDwtIHJhX2J5X3RheF9yYW5rKGNvdW50cyA9IGNvdW50c19wLAogICAgICAgICAgICAgICAgICAgICAgIHBjdCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0ID0gNCkKCmRhdGF0YWJsZShyYV9wLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgIGNhcHRpb24gPSAiVGF4b25vbWljICBjb3VudCB0YWJsZSIsCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiLAogICAgICAgICAgb3B0aW9ucyA9IGxpc3Qoc2VhcmNoID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTGVuZ3RoID0gbnJvdyhyYV9wKSkpICU+JQogIGZvcm1hdFBlcmNlbnRhZ2UoY29sdW1ucyA9IDI6bmNvbChjb3VudHNfcCksCiAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyKQoKcHJpbnQoIlJhbmdlIG9mIHJlbGF0aXZlIGFidW5kYW5jZSBvZiBCYWN0ZXJvaWRldGVzIGFuZCBGaXJtaWN1dGVzIGNvbWJpbmVkICglKSIpCnJvdW5kKDEwMCpyYW5nZShyYV9wWzEsIC0xXSArIHJhX3BbMiwgLTFdKSwgMSkKYGBgCgojIyBQQ0EgYXQgUGh5bHVtIGxldmVsCmBgYHtyIHBjYV9wX3AwLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gNn0KZHRfcGNhIDwtIHQocmFfcFssIDI6bmNvbChyYV9wKV0pCmNvbG5hbWVzKGR0X3BjYSkgPC0gcmFfcCRQaHlsdW0KCmR0X3BjYV9wIDwtIGRhdGEudGFibGUoU2FtcGxlID0gcm93bmFtZXMoZHRfcGNhKSwKICAgICAgICAgICAgICAgICAgICAgICBkdF9wY2EpCmR0X3BjYV9wIDwtIG1lcmdlKHNtcGwsCiAgICAgICAgICAgICAgICAgIGR0X3BjYV9wLAogICAgICAgICAgICAgICAgICBieSA9ICJTYW1wbGUiKQoKIyBLZWVwIG9ubHkgdGhlIHBoeWx1bSB3aXRoIG5vbi16ZXJvIGNvdW50cwp0bXAgPC0gZHRfcGNhX3BbLCA3Om5jb2woZHRfcGNhX3ApXQprZWVwX3AgPC0gY29sbmFtZXModG1wKVtjb2xTdW1zKHRtcCkgPiAwXQpkdF9wY2EgPC0gZHRfcGNhWywga2VlcF9wXQoKIyBtMSA8LSBwcmNvbXAoZHRfcGNhLAojICAgICAgICAgICAgICBjZW50ZXIgPSBUUlVFLAojICAgICAgICAgICAgICBzY2FsZS4gPSBUUlVFKQoKIyBtMSA8LSBwcmNvbXAoZHRfcGNhLAojICAgICAgICAgICAgICBjZW50ZXIgPSBGQUxTRSwKIyAgICAgICAgICAgICAgc2NhbGUuID0gRkFMU0UpCgptMSA8LSBwcmNvbXAoZHRfcGNhLAogICAgICAgICAgICAgY2VudGVyID0gVFJVRSwKICAgICAgICAgICAgIHNjYWxlLiA9IEZBTFNFKQoKc3VtbWFyeShtMSkKCiMgU2VsZWN0IFBDLXMgdG8gcGxpb3QgKFBDMSAmIFBDMikKY2hvaWNlcyA8LSAxOjIKCiMgQWRkIG1ldGEgZGF0YQpkdC5zY3IgPC0gZGF0YS50YWJsZShtMSR4WywgY2hvaWNlc10pCmR0LnNjciRTYW1wbGUgPC0gcm93bmFtZXMobTEkeCkKCmR0LnNjciA8LSBtZXJnZShzbXBsLAogICAgICAgICAgICAgICAgZHQuc2NyLAogICAgICAgICAgICAgICAgYnkgPSAiU2FtcGxlIikKZHQuc2NyCgojIExvYWRpbmdzLCBpLmUuIGFycm93cyAoZGYudikKZHQucm90IDwtIGFzLmRhdGEuZnJhbWUobTEkcm90YXRpb25bLCBjaG9pY2VzXSkKZHQucm90JGZlYXQgPC0gcm93bmFtZXMoZHQucm90KQpkdC5yb3QgPC0gZGF0YS50YWJsZShkdC5yb3QpCmR0LnJvdAoKZHQubG9hZCA8LSBtZWx0LmRhdGEudGFibGUoZHQucm90LAogICAgICAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gImZlYXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFzdXJlLnZhcnMgPSAxOjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAicGMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZS5uYW1lID0gImxvYWRpbmciKQpkdC5sb2FkJGZlYXQgPC0gZmFjdG9yKGR0LmxvYWQkZmVhdCwKICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUoZHQubG9hZCRmZWF0KSkKIyBQbG90IGxvYWRpbmdzCnAwIDwtIGdncGxvdChkYXRhID0gZHQubG9hZCwKICAgICAgICAgICAgIGFlcyh4ID0gZmVhdCwKICAgICAgICAgICAgICAgICB5ID0gbG9hZGluZykpICsKICBmYWNldF93cmFwKH4gcGMsCiAgICAgICAgICAgICBucm93ID0gMikgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2d0aXRsZSgiUEMgTG9hZGluZ3MiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKQpwMAoKdGlmZihmaWxlbmFtZSA9ICJ0bXAvcGMuMS4yX2xvYWRpbmdzX3BoeWx1bS50aWZmIiwKICAgICBoZWlnaHQgPSA1LAogICAgIHdpZHRoID0gNiwKICAgICB1bml0cyA9ICdpbicsCiAgICAgcmVzID0gMzAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDApCmdyYXBoaWNzLm9mZigpCgpwcmludChwMCkKYGBgCgpgYGB7ciBwY2FfYXhlc3B9CiMgQXhpcyBsYWJlbHMKdS5heGlzLmxhYnMgPC0gcGFzdGUoY29sbmFtZXMoZHQucm90KVsxOjJdLCAKICAgICAgICAgICAgICAgICAgICAgc3ByaW50ZignKCUwLjFmJSUgZXhwbGFpbmVkIHZhci4pJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwKm0xJHNkZXZbY2hvaWNlc11eMi9zdW0obTEkc2Rldl4yKSkpCnUuYXhpcy5sYWJzCmBgYAoKYGBge3IgYmlwbG90X2dlbl9wLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30KY250ciA8LSBkYXRhLnRhYmxlKGFnZ3JlZ2F0ZSh4ID0gZHQuc2NyJFBDMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGxpc3QoZHQuc2NyJFRyZWF0bWVudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHQuc2NyJFdlZWspLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9ICJtZWFuIiksCiAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGUoeCA9IGR0LnNjciRQQzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBsaXN0KGR0LnNjciRUcmVhdG1lbnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0LnNjciRXZWVrKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSAibWVhbiIpJHgpCgpjb2xuYW1lcyhjbnRyKSA8LSBjKCJUcmVhdG1lbnQiLAogICAgICAgICAgICAgICAgICAgICJXZWVrIiwKICAgICAgICAgICAgICAgICAgICAiUEMxIiwKICAgICAgICAgICAgICAgICAgICAiUEMyIikKCmNudHIkdG1wIDwtIGZhY3RvcihjbnRyJFRyZWF0bWVudCwKICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIk5OSyBjb250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlZlaGljbGUgY29udHJvbCAoVkMpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5OSytEQVMiKSwKICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk5OSyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOTksrREFTIikpCmNudHIkZ3JwIDwtIHBhc3RlKGNudHIkdG1wLAogICAgICAgICAgICAgICAgICBjbnRyJFdlZWssCiAgICAgICAgICAgICAgICAgIHNlcCA9ICJfIikKCiMgQmFzZWQgb24gRmlndXJlIHAwLCBrZWVwIG9ubHkgYSBmZXcgdmFyaWFibGVzIHdpdGggaGlnaCBsb2FkaW5ncyBpbiBQQzEgYW5kIFBDMi0tLS0KZHQucm90WywgcmF0aW5nOj0gKFBDMSleMiArIChQQzIpXjJdCnNldG9yZGVyKGR0LnJvdCwgLXJhdGluZykKCiMgU2VsZWN0IHRvcCAzCmR0LnJvdCA8LSBkdC5yb3RbMTozLCBdCgojIHZhci5rZWVwLm5keCA8LSB3aGljaChkdC5yb3QkZmVhdCAlaW4lIGMoLi4uKSkKIyBPciBzZWxlY3QgYWxsCiMgdmFyLmtlZXAubmR4IDwtIDM6bmNvbChkdDEpCiMgVXNlIGR0LnJvdFt2YXIua2VlcC5uZHgsXSBhbmQgZHQucm90JGZlYXRbdmFyLmtlZXAubmR4XQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnJvdCwKICAgICAgICAgICAgIGFlcyh4ID0gUEMxLAogICAgICAgICAgICAgICAgIHkgPSBQQzIpKSArCiAgIyBjb29yZF9lcXVhbCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdC5zY3IsCiAgICAgICAgICAgICBhZXMoZmlsbCA9IFRyZWF0bWVudCwKICAgICAgICAgICAgICAgICBzaGFwZSA9IGZhY3RvcihXZWVrKSksCiAgICAgICAgICAgICBzaXplID0gMywKICAgICAgICAgICAgIGFscGhhID0gMC41KSArCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMCwKICAgICAgICAgICAgICAgICAgIHkgPSAwLAogICAgICAgICAgICAgICAgICAgeGVuZCA9IDAuMipQQzEsCiAgICAgICAgICAgICAgICAgICB5ZW5kID0gMC4yKlBDMiksCiAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgxLzIsICdwaWNhcycpKSwKICAgICAgICAgICAgICAgIyBzaXplID0gMSwgCiAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fdGV4dChhZXMoeCA9IDAuMjIqUEMxLAogICAgICAgICAgICAgICAgeSA9IDAuMjIqUEMyLAogICAgICAgICAgICAgICAgbGFiZWwgPSBkdC5yb3QkZmVhdCksCiAgICAgICAgICAgICMgc2l6ZSA9IDUsCiAgICAgICAgICAgIGhqdXN0ID0gMC41KSArCiAgc2NhbGVfeF9jb250aW51b3VzKHUuYXhpcy5sYWJzWzFdKSArCiAgc2NhbGVfeV9jb250aW51b3VzKHUuYXhpcy5sYWJzWzJdKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJUcmVhdG1lbnQiLAogICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIk5OSyBjb250cm9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWZWhpY2xlIGNvbnRyb2wgKFZDKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTk5LK0RBUyIpLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoInJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3JlZW4iKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChicmVha3MgPSAxOjQsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IDIxOjI0KSArCiAgZ2VvbV9sYWJlbChkYXRhID0gY250ciwKICAgICAgICAgICAgIGFlcyh4ID0gUEMxLAogICAgICAgICAgICAgICAgIHkgPSBQQzIsCiAgICAgICAgICAgICAgICAgbGFiZWwgPSBncnAsCiAgICAgICAgICAgICAgICAgY29sb3VyID0gVHJlYXRtZW50KSwKICAgICAgICAgICAgIGFscGhhID0gMC41LAogICAgICAgICAgICAgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoZ3VpZGUgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygiTk5LIGNvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJWZWhpY2xlIGNvbnRyb2wgKFZDKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5OSytEQVMiKSwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyZWVuIikpICsKICBnZ3RpdGxlKCIiKSArCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgp0aWZmKGZpbGVuYW1lID0gInRtcC9waHlsdW1fYmlwbG90X3RydF9qYW4yMC50aWZmIiwKICAgICBoZWlnaHQgPSA3LAogICAgIHdpZHRoID0gNywKICAgICB1bml0cyA9ICdpbicsCiAgICAgcmVzID0gMzAwLAogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikKcHJpbnQocDEpCmdyYXBoaWNzLm9mZigpCgpnZ3Bsb3RseShwMSkKCiMgR2VuZXJpYyBiaXBsb3QKYmlwbG90KG0xKQpgYGAKCiMjIDMuIE9yZGVyCgojIyA0LiBGYW1pbHkKCiMgNS4gR2VudXMKIyMgQ291bnRzIGF0IEdlbnVzIGxldmVsCmBgYHtyIGNvdW50c19nLCB3YXJuaW5nPUZBTFNFLGVjaG89RkFMU0UsbWVzc2FnZT1GQUxTRX0KY291bnRzX2cgPC0gY291bnRzX2J5X3RheF9yYW5rKGR0MSA9IG90dSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JfYnkgPSAiR2VudXMiKQpzZXRvcmRlcihjb3VudHNfZywgLWBSSDAxYCkKZGF0YXRhYmxlKGNvdW50c19nLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKICAgICAgICAgIGNhcHRpb24gPSAiVGF4b25vbWljICBjb3VudCB0YWJsZSIsCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiLAogICAgICAgICAgb3B0aW9ucyA9IGxpc3Qoc2VhcmNoID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWdlTGVuZ3RoID0gbnJvdyhjb3VudHNfZykpKSAlPiUKICBmb3JtYXRDdXJyZW5jeShjb2x1bW5zID0gMjpuY29sKGNvdW50c19nKSwKICAgICAgICAgICAgICAgICBjdXJyZW5jeSA9ICIiLAogICAgICAgICAgICAgICAgIG1hcmsgPSAiLCIsCiAgICAgICAgICAgICAgICAgZGlnaXRzID0gMCkKYGBgCgojIyBSZWxhdGl2ZSBhYnVuZGFuY2UgKCUpIGF0IEdlbnVzIGxldmVsCmBgYHtyIHJhX2csIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CnJhX2cgPC0gcmFfYnlfdGF4X3JhbmsoY291bnRzID0gY291bnRzX2csCiAgICAgICAgICAgICAgICAgICAgICAgcGN0ID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgZGlnaXQgPSA0KQoKZGF0YXRhYmxlKHJhX2csCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLAogICAgICAgICAgY2FwdGlvbiA9ICJUYXhvbm9taWMgIGNvdW50IHRhYmxlIiwKICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzZWFyY2ggPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhZ2VMZW5ndGggPSBucm93KHJhX2cpKSkgJT4lCiAgZm9ybWF0UGVyY2VudGFnZShjb2x1bW5zID0gMjpuY29sKGNvdW50c19nKSwKICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDIpCmBgYAoKIyBEci4gS29uZydzIHJlcXVlc3Q6IGZpbmQgdGhlIGZvbGxvd2luZyBiYWN0ZXJpYWwgc3BlY2llcyAoZW1pYWxlZCBvbiAwNS8wNC8yMCwgMTE6NDggQU0pOiAgCiMgU3RyZXB0b2NvY2N1cyBib3ZpcywgSC4gcHlsb3JpLCBGdXNvYmFjdGVyaXVtIG51Y2xlYXR1bSwgRW50ZXJvY29jY3VzIGZhZWNhbGlzLCBMYWN0b2JhY2lsbHVzIGFjaWRvcGhpbHVzICBhbmQgIEJpZmlkb2JhY3Rlcml1bSBsb25ndW0uICAKIyBTb3VyY2U6IFtCaW9zdGFycyBRdWVzdGlvbjogRXh0cmFjdCB0aGUgJ3BoeWx1bScgYW5kICdzcGVjaWVzJyB1bmRlciAiY2xhc3NpZmljYXRpb24iIHVzaW5nIFRheGl6ZSBwYWNrYWdlIGluIFJdKGh0dHBzOi8vd3d3LmJpb3N0YXJzLm9yZy9wLzI3MzAzNy8pICAKIyBUdXRvcmlhbDogW3JPcGVuU2NpIHRheGl6ZSB0dXRvcmlhbF0oaHR0cHM6Ly9yb3BlbnNjaS5vcmcvdHV0b3JpYWxzL3RheGl6ZV90dXRvcmlhbC8pICAKYGBge3IgZmluZF9zcGVjaWVzX2Rya29uZ18wNTA0MjB9CnNwZWNpZXNsaXN0IDwtIGMoIlN0cmVwdG9jb2NjdXMgYm92aXMiLAogICAgICAgICAgICAgICAgICJIZWxpY29iYWN0ZXIgcHlsb3JpIiwKICAgICAgICAgICAgICAgICAiRnVzb2JhY3Rlcml1bSBudWNsZWF0dW0iLAogICAgICAgICAgICAgICAgICJFbnRlcm9jb2NjdXMgZmFlY2FsaXMiLAogICAgICAgICAgICAgICAgICJMYWN0b2JhY2lsbHVzIGFjaWRvcGhpbHVzIiwKICAgICAgICAgICAgICAgICAiQmlmaWRvYmFjdGVyaXVtIGxvbmd1bSIpCgp0MSA8LSB0YXhfbmFtZShxdWVyeSA9IGMoc3BlY2llc2xpc3QpLAogICAgICAgICAgICAgICBnZXQgPSBjKCJwaHlsdW0iLAogICAgICAgICAgICAgICAgICAgICAgICJjbGFzcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIm9yZGVyIiwKICAgICAgICAgICAgICAgICAgICAgICAiZmFtaWx5IiwKICAgICAgICAgICAgICAgICAgICAgICAiZ2VudXMiKSwgCiAgICAgICAgICAgICAgIGRiID0gIm5jYmkiKQoKIyBHZW51cyB0aGVzZSBzcGVjaWVzIGJlbG9uZyB0bywgZm91bmQgaW4gdGhpcyBkYXRhc2V0CnQxLjEgPC0gdW5pcXVlKHRheGFbR2VudXMgJWluJSB0MSRnZW51cywgLTFdKQp0MS4xCmBgYAoKYGBge3IgZmluZF9zcGVjaWVzX2Rya29uZ18wNTA0MjBfcGFydDJ9CiMgQ291bnQgbnVtYmVyIG9mIE9UVXMgaW4gZWFjaCBvZiB0aGVzZSBnZW51cyAoaW4gdGhpcyBkYXRhKQpmaW5kX2dlbnVzIDwtIHVuaXF1ZShvdHVbR2VudXMgJWluJSB0MS4xJEdlbnVzLCBdKQpmaW5kX2dlbnVzCgp0YmwxIDwtIGRhdGEudGFibGUodGFibGUoZmluZF9nZW51cyRHZW51cykpCmNvbG5hbWVzKHRibDEpIDwtIGMoIkdlbnVzIiwKICAgICAgICAgICAgICAgICAgICAiTl9PVFUiKQoKIyBOdW1iZXIgb2Ygc3BlY2llcyBpbiBlYWNoIG9mIHRoZXNlIGdlbnVzIChpbiBOQ0JJIHJlZmVyZW5jZSBkYXRhYmFzZSkKcm0odDIuMSkKZ2MoKQoKIyBOT1RFOiB0aGlzIGRvZXMgbm90IHdvcmsgZXZlcnkgdGltZSAtIEtFRVAgVFJZSU5HIHVudGlsIGl0IGRvZXMhCnQyLjEgPC0gZG93bnN0cmVhbSh4ID0gdDEkZ2VudXMsCiAgICAgICAgICAgICAgICAgICBkb3dudG8gPSAic3BlY2llcyIsCiAgICAgICAgICAgICAgICAgICBkYiA9ICJuY2JpIikKdGJsMiA8LSBkYXRhLnRhYmxlKEdlbnVzID0gbmFtZXModDIuMSksCiAgICAgICAgICAgICAgICAgICBOX1NwZWNpZXMgPSBsYXBwbHkodDIuMSwgbnJvdykpCgojIE1lcmdlIG51bWJlciBvZiBPVFVzIGZvdW5kIGFuZCBudW1iZXIgb2Ygc3BlY2llcyBrb3duIGZvciBlYWNoIGdlbnVzCnRibCA8LSBtZXJnZSh0YmwxLAogICAgICAgICAgICAgdGJsMiwKICAgICAgICAgICAgIGJ5ID0gIkdlbnVzIiwKICAgICAgICAgICAgIGFsbCA9IFRSVUUpCnRibCROX09UVVtpcy5uYSh0YmwkTl9PVFUpXSA8LSAwCnNldG9yZGVyKHRibCwgLU5fT1RVKQpkYXRhdGFibGUodGJsLAogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSkKYGBgCgpgYGB7ciBmaW5kX3NwZWNpZXNfZHJrb25nXzA1MDQyMF9wYXJ0M30KIyBNZWFuZCBhbmQgcmFuZ2UgcmVsYXRpdmUgYWJ1bmRhbmNlIG9mIGVhY2ggZ2VudXMKdG1wIDwtIHJhX2dbR2VudXMgJWluJSB0MSRnZW51cywgXQp0bXAxIDwtIGFwcGx5KHRtcFssIC0xXSwgCiAgICAgICAgICAgICAgTUFSR0lOID0gMSwKICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbihhKSB7CiAgICAgICAgICAgICAgICByZXR1cm4oZGF0YS50YWJsZShNZWFuID0gbWVhbihhKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNEID0gc2QoYSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNaW4gPSBtaW4oYSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNYXggPSBtYXgoYSkpKQogICAgICAgICAgICAgIH0pCm91dCA8LSBkYXRhLnRhYmxlKEdlbnVzID0gdG1wJEdlbnVzLAogICAgICAgICAgICAgICAgICByYmluZGxpc3QodG1wMSkpCmRhdGF0YWJsZShvdXQsCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFKSAlPiUKICBmb3JtYXRQZXJjZW50YWdlKGNvbHVtbnMgPSAyOjQsCiAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyKQpgYGAKCiMgU2Vzc2lvbiBJbmZvcm1hdGlvbgpgYGB7ciBpbmZvLGV2YWw9VFJVRX0Kc2Vzc2lvbkluZm8oKQpgYGA=